package com.bossly.metro;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;

import com.bossly.metro.dom.Line;
import com.bossly.metro.dom.Station;

import android.graphics.Color;
import android.graphics.Point;
import android.graphics.Rect;
import android.location.Location;

public class Metropoliten {
	public Hashtable<Integer, Station> m_stations = new Hashtable<Integer, Station>();
	public Hashtable<Integer, Line> m_lines = new Hashtable<Integer, Line>();
	public static final int RADIUS = 30;

	public Metropoliten() {
	}

	public void addStation(Station station) {
		m_stations.put(station.getId(), station);
	}

	public Station getStation(int id) {
		return m_stations.get(id);
	}

	public ArrayList<Station> findShortway(int from, int to) {
		ArrayList<Station> check = new ArrayList<Station>();
		ArrayList<Station> way = new ArrayList<Station>();

		Station finish = getStation(to);
		Station start = getStation(from);

		if (start != null && finish != null) {
			way.add(start);

			// using search algorithm
			if (from != to) {
				way.addAll(findWay(finish, from, check));
			}

			way.add(finish);
		}

		return way;
	}

	private ArrayList<Station> findWay(Station current, int finish,
			ArrayList<Station> check) {
		ArrayList<Station> way = null;
		ArrayList<Station> newway = null;

		int minWeight = Integer.MAX_VALUE;

		if (check.contains(current))
			return way;

		check.add(current);

		for (int i = 0, length = current.getStationCount(); i < length; i++) {
			Station child = current.getStation(i);

			if (child == null)
				continue;

			if (child.getId() == finish) {
				way = new ArrayList<Station>();
				break;
			} else {
				newway = findWay(child, finish, check);

				if (newway != null) {
					int weight = calWeight(newway);

					if (weight < minWeight) {
						way = newway;
						way.add(child);
						minWeight = weight;
					}
				}
			}
		}

		check.remove(current);

		return way;
	}

	private int calWeight(ArrayList<Station> newway) {
		int line = -1;
		int weight = 0;
		Station station;

		for (int i = 0, length = newway.size(); i < length; i++) {
			station = newway.get(i);

			if (station.getLine() != line) {
				weight += 2;
			} else {
				weight += 1;
			}
		}

		return weight;
	}

	/**
	 * Call once after adding.
	 */
	public void updateRelations() {
		Enumeration<Integer> keys = m_stations.keys();
		Station station;
		Station relate;

		while (keys.hasMoreElements()) {
			int key = keys.nextElement();

			station = m_stations.get(key);

			if (getLineName(station.getLine()) == null) {
				m_stations.remove(key);
				continue;
			}

			if (station.next >= 0) {
				relate = m_stations.get(station.next);

				if (relate != null)
					station.addStation(relate);
			}

			if (station.prev >= 0) {
				relate = m_stations.get(station.prev);

				if (relate != null)
					station.addStation(relate);
			}
		}
	}

	public boolean contains(int id) {
		return m_stations.containsKey(id);
	}

	public Station getNearStation(Location location) {
		Station station = null;
		Enumeration<Integer> keys = m_stations.keys();
		float minDis = Float.MAX_VALUE;

		while (keys.hasMoreElements()) {
			int key = keys.nextElement();
			Station s = getStation(key);
			float dist = s.getLocation().distanceTo(location);

			if (dist < minDis) {
				station = s;
				minDis = dist;
			}
		}

		return station;
	}

	public Line getLineName(int id) {
		return m_lines.get(id);
	}

	public void addLine(int id, String name, String color) {
		Line line = new Line();
		line.id = id;
		line.name = name;
		//line.color = Color.parseColor(color);
		m_lines.put(id, line);		
	}

	public int getStationCount() {
		return m_stations.size();
	}

	public ArrayList<Station> getStations(String constraint) {
		String filter = constraint.toLowerCase();
		ArrayList<Station> stations = new ArrayList<Station>();

		Iterator<Station> values = m_stations.values().iterator();
		Station result = null;

		for (int i = 0; values.hasNext(); i++) {
			result = values.next();

			if (filter.equalsIgnoreCase("*")
					|| result.getName().toLowerCase().startsWith(filter)
					|| result.getName().toLowerCase().startsWith(filter)) {
				stations.add(result);
			}
		}

		return stations;
	}

	public Station getStationByIndex(int which) {
		Iterator<Station> values = m_stations.values().iterator();
		Station result = null;

		for (int i = 0; values.hasNext(); i++) {
			if (i == which) {
				result = values.next();
				break;
			}

			values.next();
		}

		return result;
	}

	public Station hitStation(int x, int y) {
		Iterator<Station> values = m_stations.values().iterator();
		Station result = null;
		Rect rcHitTest;
		Point loc;

		for (int i = 0; values.hasNext(); i++) {
			result = values.next();
			loc = result.getSreenLocation();
			rcHitTest = new Rect(loc.x - RADIUS, loc.y - RADIUS,
					loc.x + RADIUS, loc.y + RADIUS);

			if (!rcHitTest.contains(x, y)) {
				result = null;
				continue;
			}

			break;
		}

		return result;
	}
}
